home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / PackLayout.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  14.8 KB  |  412 lines  |  [TEXT/CWIE]

  1. // PackLayout.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp. All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Object subclass implementing a LayoutManager similar to the TK Packer.
  10.   * See the PackConstraints class for more information about the available
  11.   * settings can be used.<p>
  12.   * <i>Note: Because Views do not call <b>layoutView()</b> whenever subviews are
  13.   * added or removed, an application using a PackLayout must explicitly call
  14.   * the PackLayout View's <b>layoutView()</b> with a zero delta width and delta
  15.   * height.  Calling <b>layoutView()</b> in this manner will cause the
  16.   * LayoutManager to properly position and size the View's subviews.</i>
  17.   *
  18.   * @see PackConstraints
  19.   * @note 1.0 added defaultConstraints
  20.   * @note 1.0 better algorithm for determining nested view preferred size
  21.   * @note 1.0 defaultConstraints are now archived
  22.   */
  23. public class PackLayout extends Object implements LayoutManager, Codable {
  24.     Hashtable   viewConstraints;
  25.     Vector      viewVector;
  26.     PackConstraints defaultConstraints;
  27.  
  28.     final static String VIEWCONSTRAINTS_KEY = "viewConstraints",
  29.                         VIEWVECTOR_KEY = "viewVector",
  30.                         DEFAULT_CONSTRAINTS_KEY = "defaultConstraints";
  31.  
  32.  
  33.     /** The PackConstraints to be used as default values, when a view
  34.       * it added to the PackLayout without specific defaults. If you
  35.       * are going to set this, you should do so before adding subviews.
  36.       * The management of the mapping between constraints and views is lazy,
  37.       * and may not happen until it is really needed.
  38.       *
  39.       */
  40.     public PackConstraints defaultConstraints() {
  41.         if (defaultConstraints == null) {
  42.             defaultConstraints = new PackConstraints();
  43.         }
  44.  
  45.         return defaultConstraints;
  46.     }
  47.  
  48.     /** Sets the default constraints. These values are used when a
  49.       * view is added to the PackLayout without specific defaults.
  50.       * You should set this before you add any subviews.
  51.       *
  52.       */
  53.     public void setDefaultConstraints(PackConstraints constraints)  {
  54.         if(!constraints.equals(defaultConstraints()))   {
  55.             int i, count;
  56.             count = viewVector.count();
  57.             for(i = 0; i < count; i++)  {
  58.                 /// This will automatically add the view to the hashtable with
  59.                 ///  the current default constraints.
  60.                 constraintsFor((View)viewVector.elementAt(i));
  61.             }
  62.         }
  63.         defaultConstraints = constraints;
  64.     }
  65.  
  66.     /** Constructs a PackLayout. */
  67.     public PackLayout()     {
  68.         super();
  69.         viewConstraints = new Hashtable();
  70.         viewVector = new Vector();
  71.     }
  72.  
  73.     /** Returns the PackConstraints object associated with <b>aView</b>.
  74.       */
  75.     public PackConstraints constraintsFor(View aView)   {
  76.         if(viewConstraints.get(aView) == null)  {
  77.             setConstraints(aView, defaultConstraints());
  78.         }
  79.         return (PackConstraints)viewConstraints.get(aView);
  80.     }
  81.  
  82.     /** Adds <b>aView</b> to the PackLayout with default PackConstraints.
  83.       * @see LayoutManager
  84.       * @see PackConstraints
  85.       */
  86.     public void addSubview(View aView)      {
  87.         viewVector.addElementIfAbsent(aView);
  88.     }
  89.  
  90.     /** Associates the PackConstraints <b>constraints</b> with <b>aView</b>.
  91.       * You usually call this method to associate non-default constraints with
  92.       * a particular View.<p>
  93.       * <i><b>Note:</b> This method adds a clone of <b>constraints</b> to
  94.       * its internal constraint container. You can therefore reconfigure and
  95.       * pass in the PackConstraints same instance on each call without no side
  96.       * effects.</i>
  97.       */
  98.     public void setConstraints(View aView, PackConstraints constraints) {
  99.         viewVector.addElementIfAbsent(aView);
  100.         viewConstraints.put(aView, constraints.clone());
  101.     }
  102.  
  103.     /** Removes <b>aView</b> from the PackLayout.
  104.       * @see LayoutManager
  105.       */
  106.     public void removeSubview(View aView)   {
  107.         viewConstraints.remove(aView);
  108.         viewVector.removeElement(aView);
  109.     }
  110.  
  111.     /** Positions and sizes its View's subviews according to the constraints
  112.       * associated with each subview.
  113.       * @see LayoutManager
  114.       */
  115.     public void layoutView(View aView, int deltaWidth, int deltaHeight) {
  116.         View curView;
  117.         int cntx,max;
  118.         int cavityX = 0, cavityY = 0;
  119.         int cavityWidth = aView.bounds.width;
  120.         int cavityHeight = aView.bounds.height;
  121.         int frameX, frameY, frameWidth, frameHeight;
  122.         int width, height, x, y;
  123.         int side, padx, pady, ipadx, ipady, anchor;
  124.         boolean expand, fillx, filly;
  125.         Vector sViews;
  126.         PackConstraints constraints;
  127.         Size preferredSize;
  128.  
  129.         sViews = aView.subviews();
  130.         max=sViews.count();
  131.         for(cntx=0 ; cntx < max ; cntx++)       {
  132.             curView     = (View)sViews.elementAt(cntx);
  133.             constraints = (PackConstraints)viewConstraints.get(curView);
  134.             if(constraints == null)
  135.                 constraints = defaultConstraints();
  136.             side        = constraints.side();
  137.             padx        = constraints.padX()*2;
  138.             pady        = constraints.padY()*2;
  139.             ipadx       = constraints.internalPadX();
  140.             ipady       = constraints.internalPadY();
  141.             expand      = constraints.expand();
  142.             fillx       = constraints.fillX();
  143.             filly       = constraints.fillY();
  144.             anchor      = constraints.anchor();
  145.  
  146.             preferredSize = preferredLayoutSize(curView);
  147.  
  148.             if ((side == PackConstraints.SIDE_TOP) || (side == PackConstraints.SIDE_BOTTOM)) {
  149.                 frameWidth = cavityWidth;
  150.                 frameHeight = preferredSize.height + pady + ipady;
  151.                 if (expand)
  152.                     frameHeight += YExpansion(curView, cavityHeight);
  153.                 cavityHeight -= frameHeight;
  154.                 if (cavityHeight < 0) {
  155.                     frameHeight += cavityHeight;
  156.                     cavityHeight = 0;
  157.                 }
  158.                 frameX = cavityX;
  159.                 if (side == PackConstraints.SIDE_TOP) {
  160.                     frameY = cavityY;
  161.                     cavityY += frameHeight;
  162.                 } else {
  163.                     frameY = cavityY + cavityHeight;
  164.                 }
  165.             } else {
  166.                 frameHeight = cavityHeight;
  167.                 frameWidth = preferredSize.width + padx + ipadx;
  168.                 if (expand)
  169.                     frameWidth += XExpansion(curView, cavityWidth);
  170.                 cavityWidth -= frameWidth;
  171.                 if (cavityWidth < 0) {
  172.                     frameWidth += cavityWidth;
  173.                     cavityWidth = 0;
  174.                 }
  175.                 frameY = cavityY;
  176.                 if (side == PackConstraints.SIDE_LEFT) {
  177.                     frameX = cavityX;
  178.                     cavityX += frameWidth;
  179.                 } else {
  180.                     frameX = cavityX + cavityWidth;
  181.                 }
  182.             }
  183.  
  184.             width = preferredSize.width + ipadx;
  185.             if ((fillx) || (width > (frameWidth - padx)))
  186.                 width = frameWidth - padx;
  187.  
  188.             height = preferredSize.height + ipady;
  189.             if ((filly) || (height > (frameHeight - pady)))
  190.                 height = frameHeight - pady;
  191.  
  192.             padx /= 2;
  193.             pady /= 2;
  194.  
  195.             switch (anchor) {
  196.             case PackConstraints.ANCHOR_NORTH:
  197.                 x = frameX + (frameWidth - width)/2;
  198.                 y = frameY + pady;
  199.                 break;
  200.             case PackConstraints.ANCHOR_NORTHEAST:
  201.                 x = frameX + frameWidth - width - padx;
  202.                 y = frameY + pady;
  203.                 break;
  204.             case PackConstraints.ANCHOR_EAST:
  205.                 x = frameX + frameWidth - width - padx;
  206.                 y = frameY + (frameHeight - height)/2;
  207.                 break;
  208.             case PackConstraints.ANCHOR_SOUTHEAST:
  209.                 x = frameX + frameWidth - width - padx;
  210.                 y = frameY + frameHeight - height - pady;
  211.                 break;
  212.             case PackConstraints.ANCHOR_SOUTH:
  213.                 x = frameX + (frameWidth - width)/2;
  214.                 y = frameY + frameHeight - height - pady;
  215.                 break;
  216.             case PackConstraints.ANCHOR_SOUTHWEST:
  217.                 x = frameX + padx;
  218.                 y = frameY + frameHeight - height - pady;
  219.                 break;
  220.             case PackConstraints.ANCHOR_WEST:
  221.                 x = frameX + padx;
  222.                 y = frameY + (frameHeight - height)/2;
  223.                 break;
  224.             case PackConstraints.ANCHOR_NORTHWEST:
  225.                 x = frameX + padx;
  226.                 y = frameY + pady;
  227.                 break;
  228.             case PackConstraints.ANCHOR_CENTER:
  229.             default:
  230.                 x = frameX + (frameWidth - width)/2;
  231.                 y = frameY + (frameHeight - height)/2;
  232.                 break;
  233.             }
  234.  
  235.             curView.setBounds(x, y, width, height);
  236.         }
  237.         return;
  238.     }
  239.  
  240.     private int XExpansion(View current, int cavityWidth) {
  241.         PackConstraints constraints;
  242.         int numExpand, minExpand, curExpand, childWidth;
  243.         int padx, ipadx, side;
  244.         boolean expand;
  245.         int x,max;
  246.         View curView;
  247.  
  248.         minExpand = cavityWidth;
  249.         numExpand = 0;
  250.  
  251.         max=viewVector.count();
  252.         for(x=viewVector.indexOf(current) ; x < max ; x++)        {
  253.             curView         = (View)viewVector.elementAt(x);
  254.             constraints     = (PackConstraints)viewConstraints.get(curView);
  255.             if(constraints == null)
  256.                 constraints = defaultConstraints();
  257.             padx            = constraints.padX()*2;
  258.             ipadx           = constraints.internalPadX();
  259.             expand          = constraints.expand();
  260.             side            = constraints.side();
  261.  
  262.             childWidth      = preferredLayoutSize(curView).width + padx + ipadx;
  263.  
  264.             if ((side == PackConstraints.SIDE_TOP) || (side == PackConstraints.SIDE_BOTTOM)) {
  265.                 curExpand = (cavityWidth - childWidth)/numExpand;
  266.                 if (curExpand < minExpand)
  267.                     minExpand = curExpand;
  268.             } else {
  269.                 cavityWidth -= childWidth;
  270.                 if (expand)
  271.                     numExpand++;
  272.             }
  273.         }
  274.  
  275.         curExpand = cavityWidth/numExpand;
  276.         if (curExpand < minExpand)
  277.             minExpand = curExpand;
  278.  
  279.         if (minExpand < 0)
  280.             return 0;
  281.         else
  282.             return minExpand;
  283.  
  284.     }
  285.  
  286.     private int YExpansion(View current, int cavityHeight) {
  287.         PackConstraints constraints;
  288.         int numExpand, minExpand, curExpand, childHeight, pady, ipady;
  289.         boolean expand;
  290.         int side;
  291.         int x,max;
  292.         View curView;
  293.  
  294.         minExpand = cavityHeight;
  295.         numExpand = 0;
  296.  
  297.         max=viewVector.count();
  298.         for(x=viewVector.indexOf(current) ; x < max ; x++)        {
  299.             curView         = (View)viewVector.elementAt(x);
  300.             constraints     = (PackConstraints)viewConstraints.get(curView);
  301.             if(constraints == null)
  302.                 constraints = defaultConstraints();
  303.             pady            = constraints.padY()*2;
  304.             ipady           = constraints.internalPadY();
  305.             expand          = constraints.expand();
  306.             side            = constraints.side();
  307.  
  308.             childHeight     = preferredLayoutSize(curView).height + pady + ipady;
  309.  
  310.             if ((side == PackConstraints.SIDE_LEFT) || (side == PackConstraints.SIDE_RIGHT)) {
  311.                 curExpand = (cavityHeight - childHeight)/numExpand;
  312.                 if (curExpand < minExpand)
  313.                     minExpand = curExpand;
  314.             } else {
  315.                 cavityHeight -= childHeight;
  316.                 if (expand)
  317.                     numExpand++;
  318.             }
  319.         }
  320.  
  321.         curExpand = cavityHeight/numExpand;
  322.         if (curExpand < minExpand)
  323.             minExpand = curExpand;
  324.  
  325.         if (minExpand < 0)
  326.             return 0;
  327.         else
  328.             return minExpand;
  329.  
  330.     }
  331.  
  332.     private Rect containedRect(View target) {
  333.         int  x, max;
  334.         Rect maxRect = new Rect(0,0,0,0);
  335.         Vector sViews;
  336.         Rect tmpBounds;
  337.  
  338.         sViews = target.subviews();
  339.         if(sViews == null || sViews.count() < 1)    {
  340.             return new Rect(target.bounds.x, target.bounds.y,
  341.                         target.minSize().width, target.minSize().height);
  342.         }
  343.  
  344.         target.layoutView(0,0);
  345.  
  346.         max = sViews.count();
  347.         for(x=0 ; x < max ; x++)  {
  348.             if(x == 0)
  349.                 maxRect = containedRect((View)sViews.elementAt(x));
  350.             tmpBounds = containedRect((View)sViews.elementAt(x));
  351.             maxRect.unionWith(tmpBounds);
  352.         }
  353.  
  354.         return maxRect;
  355.     }
  356.  
  357.     /** This is the primative method that determines what the right size is
  358.       * for <b>target</b> current implmentation simply returns target.minSize().
  359.       * If minSize() returns (0, 0), we will try to calculate a minimum size
  360.       * based on the subviews of the <b>target</b>. The algorithm calculates a
  361.       * bounding Rect small enough to contain all subviews.
  362.       * All the layout code calls this to determine the size of child views.
  363.       *
  364.       */
  365.     public Size preferredLayoutSize(View target) {
  366.         Size minSize = target.minSize();
  367.         if(minSize.width != 0 || minSize.height != 0)
  368.             return minSize;
  369.  
  370.         Rect aRect = containedRect(target);
  371.         return new Size(aRect.x+aRect.width, aRect.y+aRect.height);
  372.     }
  373.  
  374. /// Codable Interface
  375.     /** Describes the PackLayout class' coding information.
  376.       * @see Codable#describeClassInfo
  377.       */
  378.     public void describeClassInfo(ClassInfo info)   {
  379.         info.addClass("netscape.application.PackLayout", 2);
  380.         info.addField(VIEWCONSTRAINTS_KEY, OBJECT_TYPE);
  381.         info.addField(VIEWVECTOR_KEY, OBJECT_TYPE);
  382.         info.addField(DEFAULT_CONSTRAINTS_KEY, OBJECT_TYPE);
  383.  
  384.     }
  385.  
  386.     /** Encodes the PackLayout.
  387.       * @see Codable#encode
  388.       */
  389.     public void decode(Decoder decoder) throws CodingException {
  390.         viewConstraints = (Hashtable)decoder.decodeObject(VIEWCONSTRAINTS_KEY);
  391.         viewVector = (Vector)decoder.decodeObject(VIEWVECTOR_KEY);
  392.         if (decoder.versionForClassName("netscape.application.PackLayout") > 1) {
  393.             defaultConstraints = (PackConstraints)decoder.decodeObject(DEFAULT_CONSTRAINTS_KEY);
  394.         }
  395.     }
  396.  
  397.     /** Decodes the PackLayout.
  398.       * @see Codable#decode
  399.       */
  400.     public void encode(Encoder encoder) throws CodingException {
  401.         encoder.encodeObject(VIEWCONSTRAINTS_KEY, viewConstraints);
  402.         encoder.encodeObject(VIEWVECTOR_KEY, viewVector);
  403.         encoder.encodeObject(DEFAULT_CONSTRAINTS_KEY, defaultConstraints);
  404.     }
  405.  
  406.     /** Finishes the PackLayout's decoding.
  407.       * @see Codable#finishDecoding
  408.       */
  409.     public void finishDecoding() throws CodingException {
  410.     }
  411. }
  412.